﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class AnimalCtrl : MonoBehaviour
{
    public float health;

    public string amType;
    public float range;
    public float maxSpeed;
    public float maxTorque;
    public Rigidbody rd;
    public NeuralNetwork nn;
    public Genome genome;
    public double fit;
    public List<Transform> eyes;
    public int eyeCount;
    public float angle;
    public bool isDraw;
    public double[] inputs;
    public double[] weights;
    public int[] splitPoints;

    public float aliveTime;
    public bool isActiveSpeed;
    public Slider slider;
    void Start()
    {
        rd = GetComponent<Rigidbody>();

        for (int i = eyeCount - 1; i >= 0; i--)
        {
            GameObject go = new GameObject(eyes.Count.ToString());
            go.transform.SetParent(transform);
            go.transform.localPosition = Vector3.zero;
            go.transform.localRotation = Quaternion.Euler(new Vector3(0, -i * angle));
            eyes.Add(go.transform);
        }

        for (int i = 1; i < eyeCount; i++)
        {
            GameObject go2 = new GameObject(eyes.Count.ToString());
            go2.transform.SetParent(transform);
            go2.transform.localPosition = Vector3.zero;
            go2.transform.localRotation = Quaternion.Euler(new Vector3(0, i * angle));
            eyes.Add(go2.transform);
        }

        ReSetPosition(transform);
    }

    void Update()
    {
        Run();
        CheckDie();
        fit = genome.fitness;
        weights = genome.weights;
        splitPoints = nn.splitPoints;
        slider.value = health / 50f;
        slider.transform.parent.rotation = Camera.main.transform.rotation;
    }

    public void ReSetPosition(Transform startPosition)
    {
        transform.position = startPosition.position + new Vector3(Random.Range(-range / 2f, range / 2f), 0, Random.Range(-range / 2f, range / 2f));
        transform.rotation = startPosition.rotation;
    }

    private void CheckDie()
    {
        aliveTime += Time.deltaTime;
        genome.fitness = aliveTime;
        health -= isActiveSpeed ? Time.deltaTime * (amType == "A" ? 2 : 3.5f) : Time.deltaTime;
        if (health <= 0)
        {
            health = 0;
            gameObject.SetActive(false);
        }
    }

    private void Run()
    {
        inputs = new double[eyes.Count * 4 + 1];
        inputs[inputs.Length - 1] = health / 50f;
        for (int i = 0; i < eyes.Count; i++)
        {
            RaycastHit hit;
            if (Physics.Raycast(transform.position, eyes[i].forward, out hit, range, 1 << 8))
            {
                inputs[i * 4] = (1 - hit.distance / range);
                if (hit.collider.tag == "Food")
                {
                    inputs[i * 4 + 1] = 0;
                    inputs[i * 4 + 2] = 0;
                    inputs[i * 4 + 3] = 1;
                    if (isDraw)
                    {
                        Debug.DrawLine(transform.position, hit.point, Color.red);
                    }
                }
                else if (hit.collider.tag == "A")
                {
                    inputs[i * 4 + 1] = 0;
                    inputs[i * 4 + 2] = 1;
                    inputs[i * 4 + 3] = 0;
                    if (isDraw)
                    {
                        Debug.DrawLine(transform.position, hit.point, Color.red);
                    }
                }
                else if (hit.collider.tag == "B")
                {
                    inputs[i * 4 + 1] = 1;
                    inputs[i * 4 + 2] = 0;
                    inputs[i * 4 + 3] = 0;
                    if (isDraw)
                    {
                        Debug.DrawLine(transform.position, hit.point, Color.red);
                    }
                }

            }
            else
            {
                inputs[i * 4 + 1] = 0;
                inputs[i * 4 + 2] = 0;
                inputs[i * 4 + 3] = 0;
                if (isDraw)
                {
                    Debug.DrawLine(transform.position, transform.position + eyes[i].forward * range, Color.cyan);
                }
            }
        }


        double[] outputs = nn.Run(inputs);
        rd.angularVelocity = transform.up * maxTorque * (float)outputs[1];
        isActiveSpeed = outputs[2] > 0;
        rd.velocity = transform.forward * maxSpeed * (float)outputs[0] * (isActiveSpeed ? (amType == "A" ? 2 : 3) : 1);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (amType == "A" && other.gameObject.tag == "Food")
        {
            health += 10;
            if (health > 50) health = 50;
            other.transform.position = new Vector3(Random.Range(-30, 30), 0, Random.Range(-30, 30));
        }
        if (amType == "B" && other.gameObject.tag == "A")
        {
            health += 20;
            if (health > 50) health = 50;
            other.gameObject.GetComponent<AnimalCtrl>().health = 0;
        }
    }
}
